package com.xy.iot.netty.handle;

import cn.hutool.core.util.*;
import cn.hutool.json.JSONUtil;
import com.xy.iot.common.enums.MessageFormatDataEnum;
import com.xy.iot.common.message.BaseMessage;
import com.xy.iot.common.result.message.JSONMessageData;
import com.xy.iot.common.utils.CommonUtil;
import com.xy.iot.common.utils.IpUtil;
import com.xy.iot.netty.channel.BaseChannel;
import com.xy.iot.netty.device.DeviceServerChannel;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;
/**
 * 类功能说明：自定义解码器，主要是用来解决半包积累的问题
 *   解码器：
 *      负责处理入站 《InboundHandler》数据
 *      负责处理出站《OutboundHandler》 数据
 *                 Netty里面提供默认的编解码器，也支持自定义编解码器
 *                 Encoder:编码器
 *                 Decoder:解码器
 *                 Codec:编解码器
 *   Decoder对应的就是ChannelInboundHandler，主要就是字节数组转换为消息对象
 *   主要是两个方法
 *             decode
 *             decodeLast
 *   抽象解码器
 *             1)ByteToMessageDecoder
 *                 用于将字节转为消息，需要检查缓冲区是否有足够的字节
 *             2)ReplayingDecoder
 *                 继承ByteToMessageDecoder，不需要检查缓冲区是否有足够的字节，但是ReplayingDecoder速度略满于ByteToMessageDecoder，不是所有的ByteBuf都支持
 *                 选择：项目复杂性高则使用ReplayingDecoder，否则使用 ByteToMessageDecoder
 *             3）MessageToMessageDecoder
 *                 用于从一种消息解码为另外一种消息（例如POJO到POJO）
 *    解码器具体的实现，用的比较多的是(更多是为了解决TCP底层的粘包和拆包问题)
 *              1)DelimiterBasedFrameDecoder： 指定消息分隔符的解码器
 *              2)LineBasedFrameDecoder: 以换行符为结束标志的解码器
 *              3)FixedLengthFrameDecoder：固定长度解码器
 *              4)LengthFieldBasedFrameDecoder：message = header+body, 基于长度解码的通用解码器
 *              5)StringDecoder：文本解码器，将接收到的对象转化为字符串，一般会与上面的进行配合，然后在后面添加业务handle
 *      Byte消息解码器
 */
@Slf4j
public class ByteServerMessageDecoder extends ByteToMessageDecoder {
    private final Class<? extends BaseMessage> baseMessage;
    public ByteServerMessageDecoder(Class<? extends BaseMessage> baseMessage) {
        this.baseMessage = baseMessage;
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        try {
            byte[] array = new byte[in.readableBytes()];
            in.readBytes(array);
            JSONMessageData messageData = CommonUtil.getEncodingData(array);
            if (baseMessage!=null && messageData != null){
                BaseChannel deviceChannel = new DeviceServerChannel(ctx.channel());
                messageData.setDeviceIp(IpUtil.getAddress(ctx.channel().remoteAddress()));
                if (ObjectUtil.isNull(messageData.getDeviceGroup())){
                    messageData.setDeviceGroup(deviceChannel.name());
                }
                out.add(messageData);
                //log.info("接收到待处理指令：{}", JSON.toJSONString(everyData));
            }else {
                String content = StrUtil.str(array, CharsetUtil.CHARSET_UTF_8);
                log.info("接收到待处理指令：{}",content);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw e;
        }
    }
}
